package com.hnx.admin.aurora.system.service.impl;

import com.hnx.admin.aurora.annotation.RepeatValidator;
import com.hnx.admin.aurora.api.cache.CacheAPI;
import com.hnx.admin.aurora.enums.BusinessType;
import com.hnx.admin.aurora.redis.RedisCache;
import com.hnx.admin.aurora.security.utils.SecurityUtil;
import com.hnx.admin.aurora.system.domain.convert.menu.MenuConvert;
import com.hnx.admin.aurora.system.domain.dto.menu.entity.MenuDTO;
import com.hnx.admin.aurora.system.domain.dto.role.entity.RoleDTO;
import com.hnx.admin.aurora.system.domain.param.menu.form.MenuForm;
import com.hnx.admin.aurora.system.domain.param.menu.query.MenuQuery;
import com.hnx.admin.aurora.system.domain.vo.menu.entity.MenuVO;
import com.hnx.admin.aurora.system.domain.vo.user.entity.UserDetailVO;
import com.hnx.admin.aurora.system.domain.vo.user.entity.UserVO;
import com.hnx.admin.aurora.system.mapper.menu.MenuMapper;
import com.hnx.admin.aurora.system.mapper.role.RoleMapper;
import com.hnx.admin.aurora.system.service.MenuService;
import com.hnx.admin.aurora.utils.TreeUtil;
import com.hnx.admin.aurora.web.exception.user.PermissionEmptyException;
import com.hnx.admin.aurora.web.json.ResultJson;
import com.hnx.admin.aurora.web.json.TreeNodeVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;

/*
创建人： 倔强的头发
创建时间：2025/6/17
功能描述:

*/
@Service
@RequiredArgsConstructor
public class MenuServiceImpl implements MenuService, CacheAPI {
    private final MenuMapper menuMapper;
    private final MenuConvert menuConvert;
    private final RoleMapper roleMapper;
    private final RedisCache redisCache;

    @Override
    public Set<String> getPermissionByUser(UserVO userVO) {
        Set<String> perms = new HashSet<String>();
        if (userVO.isAdmin()) {
            perms.add(ALL_PERMISSION);
            return perms;
        }
        return menuMapper.getPermissionByUserId(userVO.getUserId()).orElseThrow(PermissionEmptyException::new);
    }

    @Override
    public List<MenuVO> selectMenuTreeByUser(UserVO userVO) {
        List<MenuDTO> list = null;
        if (userVO.isAdmin()) {
            list = menuMapper.selectMenuAll();
        } else {
            list = menuMapper.selectMenuTreeByUserId(userVO.getUserId());
        }
        if (list == null || list.size() == 0) {
            return null;
        }
        return menuConvert.toList(list);
    }
    private List<MenuDTO> getMenuList(MenuQuery menu){
        UserDetailVO userDetailVO = (UserDetailVO) SecurityUtil.getPrincipal();
        UserVO user = userDetailVO.getUserVO();
        menu.setUserId(user.getUserId());
        menu.setAdmin(user.isAdmin());
        return menuMapper.selectMenuListByUser(menu);
    }
    @Override
    public ResultJson roleMenuTreeselect(String roleId) {
        List<MenuDTO> list = getMenuList(new  MenuQuery());
        List<TreeNodeVO> nodeList = menuConvert.toTreeList(list);
        List<String> longs = selectMenuListByRoleId(roleId);
        return ResultJson.success().add("menus", TreeUtil.buildTree(nodeList,TreeNodeVO::getId)).add("checkedKeys",longs);
    }

    @Override
    public List<String> selectMenuListByRoleId(String roleId) {
        RoleDTO role = roleMapper.selectRoleById(roleId);
        return menuMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly());
    }

    @Override
    public ResultJson selectMenuTreeList() {
        UserDetailVO userDetailVO = (UserDetailVO) SecurityUtil.getPrincipal();
        if(Objects.nonNull(userDetailVO)){
            UserVO user = userDetailVO.getUserVO();
            MenuQuery menu =new MenuQuery();
            menu.setUserId(user.getUserId());
            menu.setAdmin(user.isAdmin());
            List<MenuDTO> list = menuMapper.selectMenuListByUser(menu);
            List<TreeNodeVO> menus = menuConvert.toTreeList(list);
            return ResultJson.data(TreeUtil.buildTree(menus,TreeNodeVO::getId));
        }
        return ResultJson.fail();
    }

    @Override
    public ResultJson selectMenuList(MenuQuery menu) {
        List<MenuDTO> menuList = getMenuList(menu);
        List<MenuVO> list = menuConvert.toList(menuList);
        return ResultJson.success().add("data",TreeUtil.buildTree(list,MenuVO::getMenuId, Comparator.comparing(MenuVO::getOrderNum)));
    }

    @Override
    @RepeatValidator(type = BusinessType.UPDATE)
    public ResultJson updateMenu(MenuForm menu) {
        if(menu.getMenuId()==menu.getParentId())
        {
            throw new RuntimeException("修改菜单'" + menu.getMenuName() + "'失败，上级菜单不能选择自己");
        }
        int res = menuMapper.updateMenu(menu);
        if(res > 0){
            clearRedis();
        }
        return ResultJson.condition(res);
    }

    @Override
    @RepeatValidator
    public ResultJson insertMenu(MenuForm menu) {
        int res = menuMapper.insertMenu(menu);
        if(res > 0){
            clearRedis();
        }
        return ResultJson.condition(res);
    }

    @Override
    public ResultJson deleteMenuById(String menuId) {
        UserDetailVO userDetailVO = (UserDetailVO)SecurityUtil.getPrincipal();
        UserVO userVO = userDetailVO.getUserVO();
        List<MenuVO> list = selectMenuTreeByUser(userVO);
        if(list.stream().anyMatch(n -> n.getParentId() .equals(menuId))){
            throw new RuntimeException("存在子菜单,不允许删除");
        }
        if(checkMenuExistRole(menuId)){
            throw new RuntimeException("菜单已分配,不允许删除");
        }
        int res = menuMapper.deleteMenuById(menuId);
        if(res > 0){
            clearRedis();
        }
        return ResultJson.condition(res);
    }

    @Override
    public boolean checkMenuExistRole(String menuId) {
        return menuMapper.checkMenuExistRole(menuId) > 0;
    }

    @Override
    public ResultJson selectMenuById(String menuId) {
        MenuDTO menuDTO = menuMapper.selectMenuById(menuId);
        return ResultJson.data(menuDTO);
    }

    private void clearRedis(){
        UserDetailVO userDetailVO = (UserDetailVO)SecurityUtil.getPrincipal();
        UserVO userVO = userDetailVO.getUserVO();
        String userId = String.valueOf(userVO.getUserId());
        String cacheKey = SYS_MENU_KEY + (userVO.isAdmin() ? "admin" : userId);
        if(redisCache.hasKey(cacheKey)){
            redisCache.deleteObject(cacheKey);
        }
    }
}
